#include "Hall.h"
#include "PlayerBase.h"
#include "RoomBase.h"
#include "StackTrace.h"
#include "GateSessionBase.h"
#include "GateSessionManager.h"
#include "SessionManager.h"
#include "ServerManager.h"
#include "RpcSessionBase.h"
#include "ActivityManager.h"
#include <vector>
using namespace std;

#include "Utils.h"
#include "msg_msgid.h"
#include "msg_errno.h"
#include "msg_common.h"
#include "msg_gate.h"
#include "msg_center.h"
#include "msg_roomcenter.h"
#include "msg_record.h"
#include "msg_msgserver.h"

SINGLETON_CLASS_INIT(CHall);

void CHall::Fini()
{
    if( m_roomTimerId != -1 )
    {
        CServerManager::Instance().DelTimer( m_roomTimerId );
    }
    if( m_logTimerId != -1 )
    {
        CServerManager::Instance().DelTimer( m_logTimerId );
    }
    if( m_resTimerId != -1 )
    {
        CServerManager::Instance().DelTimer( m_resTimerId );
    }

	if (m_gameTimesTimerId != -1) {
        CServerManager::Instance().DelTimer( m_gameTimesTimerId);
	}
    CRoomManager::Instance().Fini();
    CTeamManager::Instance().Fini();
    if( m_gamelogMgr )
    {
        m_gamelogMgr->Stop();
        SAFE_DELETE( m_gamelogMgr );
    }
    NotifyRoomCenterServerStop();
}

s32 CHall::RoomCount()
{
	return m_roomCount;
}

s32 CHall::MinRoomPlayerCount()
{
	return m_minRoomPlayerCount;
}

s32 CHall::MaxRoomPlayerCount()
{
	return m_maxRoomPlayerCount;
}

s32 CHall::MaxRoomBeholderCount()
{
	return m_maxRoomBeholderCount;
}

s32 CHall::MaxPlayerCount()
{
	return m_maxPlayerCount;
}

s32 CHall::CurPlayerCount()
{
	return (s32)m_playersIpMap.size();
}

CRoomBase* CHall::FindRoom(s32 roomid)
{
	if( roomid < 0 || roomid >= RoomCount() )
	{
		return NULL;
	}
	return m_rooms[ roomid ];
}

CPlayerBase* CHall::FindPlayer(u64 gateid, u64 clientid)
{
	map<u64, map<u64, CPlayerBase*> >::iterator it = m_playersPosMap.find( gateid );
	if( it != m_playersPosMap.end() )
	{
		map<u64, CPlayerBase*>::iterator _it = it->second.find( clientid );
		if( _it != it->second.end() )
		{
			return _it->second;
		}
	}
	return NULL;
}

CPlayerBase* CHall::FindPlayer(u64 userid)
{
	map<u64, CPlayerBase*>::iterator it = m_playersIpMap.find( userid );
	if( it != m_playersIpMap.end() )
	{
		return it->second;
	}
	return NULL;
}

void CHall::Close(u64 gateid, u64 clientid)
{
    gateproto::ServerGateCloseClient req;
    req.clientid.push_back( clientid );
	CGateSessionBase *gate = (CGateSessionBase*)CSessionManager::Instance().FindServer( gateid );
	if( gate )
	{
		gate->SendMsgToGate( msgid::SG_CLOSE_CLIENT, req );
	}
	else
	{
		LOG_ERROR( "CHall::Close not found gate. gateid[%llu] clientid[%llu]",
			gateid, clientid );
	}
}

void CHall::SendMsg(u64 gateid, u64 clientid, s32 msgid, const IMessage &msg)
{
	CGateSessionBase *gate = (CGateSessionBase*)CSessionManager::Instance().FindServer( gateid );
	if( gate )
	{
		gate->SendMsgToClient( clientid, msgid, msg );
	}
	else
	{
		LOG_ERROR( "CHall::SendMsg not found gate. gateid[%llu] clientid[%llu] msgid[%d]",
			gateid, clientid, msgid );
	}
}

void CHall::BroadcastMsg(s32 msgid, const IMessage &msg)
{
}

s32 CHall::AddTimer(u32 elapse, SGLib::CallBackFunc func, void *data, s32 len, bool isPersist)
{
	return CServerManager::Instance().AddTimer( elapse, func, data, len, isPersist );
}

void CHall::DelTimer(s32 timerid)
{
	return CServerManager::Instance().DelTimer( timerid );
}

void CHall::KickOut(CPlayerBase &player, s32 reason)
{
}

CPlayerBase* CHall::PlayerEnterHall(u64 gateid, u64 clientid, u64 userid)
{
    CPlayerBase *player = _GetFreePlayer();
    SELF_ASSERT( player, return NULL; );
    player->InitPlayer( gateid, clientid, userid );

	CPlayerBase *old = FindPlayer( userid );
    SELF_ASSERT( !old, return NULL; );
	
    _AddPlayer( gateid, clientid, userid, *player );
	
	player->SetState( CPlayerBase::E_PlayerState_Hall );
	
	LOG_INFO( "PlayerEnterHall player[%llu,%llu][%llu]", gateid, clientid, userid );
    return player;
}

void CHall::PlayerLeaveHall(CPlayerBase &player, s32 reason)
{
	CRoomBase *room = player.GetRoom();
	if( room )
	{
		s32 _ret = errorcode::E_ErrorCode_Success;
		if( (_ret=room->CanLeave(player, reason)) != errorcode::E_ErrorCode_Success )
		{
            player.SetOffline( true );
			LOG_INFO( "PlayerLeaveHall player[%llu,%llu][%llu] can not leave now, addistatus[%u] ret[%d]", 
				player.GateId(), player.ClientId(), player.UserId(), player.AddiStatus(), _ret );
            commonproto::SCUserStateNtf ntf;
            ntf.state = player.AddiStatus();
            ntf.seat = player.GetSeatNo();
            room->BroadcastMsg( commonproto::SC_USER_STATE_NTF, ntf );
			return;
		}
		room->PlayerLeave( player, reason );
	}

	bool ret = _RemovePlayer( player.GateId(), player.ClientId(), player.UserId() );
	//SELF_ASSERT( ret, return; );
	LOG_INFO( "PlayerLeaveHall player[%llu,%llu][%llu] reason[%d] ret[%d]", 
        player.GateId(), player.ClientId(), player.UserId(), reason, ret?1:0 );
    
    // update activity data
    player.FlushUserActivityData();
    // update game data
    player.FlushUserGameData();
    // update win money data
    player.UpdateWinMoneyData( 0, true );

    u64 userid = player.UserId();
	player.SetState( CPlayerBase::E_PlayerState_Idle );
	player.OnLeaveHall();
    _PutPlayer( &player );

    CTeamManager::Instance().RemoveUser( player.UserId() );

    // 通知下线
    _NotifyCenterUserOffline( userid );
}

void CHall::PlayerEnterRoom(CPlayerBase &player, CRoomBase &room, int seatno, const std::string &passwd)
{
    if( player.State() != CPlayerBase::E_PlayerState_Hall )
	{
		LOG_ERROR( "PlayerEnterRoom player state error. player[%llu,%llu][%llu] state[%d]", 
			player.GateId(), player.ClientId(), player.UserId(), player.State() );
		return;
	}
    // 检查是否可以进房间	
    s32 rseat = seatno;
    if( seatno == commonproto::E_SeatType_AutoSeat )
    {
        rseat = room.FindFreeSeat();
    }
    
    s32 ret = room.CanEnter( player, rseat, passwd );
    LOG_INFO( "[%s][%s][%d] user[%llu] room[%d] seatno[%d] realseat[%d] passwd[%s] ret[%d]",
		__FILE__, __FUNCTION__, __LINE__, player.UserId(), room.Id(), seatno, rseat, passwd.c_str(), ret );
    commonproto::SCEnterRoomRsp rsp;
    rsp.result = ret;
    rsp.roomid = room.Id();
    rsp.seatno = rseat;
    player.SendMsg( commonproto::SC_ENTER_ROOM_RSP, rsp );
    if( ret == errorcode::E_ErrorCode_Success )
    {
        room.PlayerEnter( player, rseat, passwd );
    }
}

void CHall::PlayerLeaveRoom(CPlayerBase &player, s32 reason)
{
	CRoomBase *room = player.GetRoom();
    if( !room )
    {
		LOG_ERROR( "PlayerLeaveRoom player not in room. player[%llu,%llu][%llu]", 
			player.GateId(), player.ClientId(), player.UserId() );
        return;
    }
    
    if( player.State() == CPlayerBase::E_PlayerState_Hall )
	{
		LOG_ERROR( "PlayerLeaveRoom player state error. player[%llu,%llu][%llu] state[%d]", 
			player.GateId(), player.ClientId(), player.UserId(), player.State() );
		return;
	}

	s32 ret = room->CanLeave( player, reason );
    commonproto::SCLeaveRoomRsp rsp;
	rsp.result = ret;
	player.SendMsg( commonproto::SC_LEAVE_ROOM_RSP, rsp );

	LOG_INFO( "[%s][%s][%d] user[%llu] room[%d] seatno[%d] ret[%d] reason[%d]",
		__FILE__, __FUNCTION__, __LINE__, player.UserId(), room->Id(), player.GetSeatNo(), ret, reason );
    if( ret == errorcode::E_ErrorCode_Success )
    {
        room->PlayerLeave( player, reason );
    }
}

void CHall::PlayerSitDown(CPlayerBase &player, int seatno)
{
    CRoomBase *room = player.GetRoom();
	if( !room )
    {
		LOG_ERROR( "PlayerSitDown player not in room. player[%llu,%llu][%llu]", 
			player.GateId(), player.ClientId(), player.UserId() );
        return;
    }
    
    if( player.State() != CPlayerBase::E_PlayerState_WaitInRoom )
	{
		LOG_ERROR( "PlayerSitDown player state error. player[%llu,%llu][%llu] state[%d]", 
			player.GateId(), player.ClientId(), player.UserId(), player.State() );
		return;
	}
    
    s32 oldseat = seatno;
    if( seatno == commonproto::E_SeatType_AutoSeat )
    {
        seatno = room->FindFreeSeat();
    }

    if( seatno < 0 || seatno >= MaxRoomPlayerCount() )
    {
		LOG_ERROR( "PlayerSitDown seatno[%d] error. player[%llu,%llu][%llu]", 
			seatno, player.GateId(), player.ClientId(), player.UserId() );
		return;
    }

	s32 ret = room->CanSitDown( player, seatno );
    commonproto::SCSitDownRsp rsp;
	rsp.result = ret;
    rsp.seatno = seatno;
	player.SendMsg( commonproto::SC_SITDOWN_RSP, rsp );

	LOG_INFO( "[%s][%s][%d] user[%llu] room[%d] seatno[%d] oldseat[%d] ret[%d]",
		__FILE__, __FUNCTION__, __LINE__, player.UserId(), room->Id(), seatno, oldseat, ret );
    if( ret == errorcode::E_ErrorCode_Success )
    {
        room->PlayerSitDown( player, seatno );
    }
}

void CHall::PlayerStandUp(CPlayerBase &player)
{
    CRoomBase *room = player.GetRoom();
    if( !room )
    {
		LOG_ERROR( "PlayerStandUp player not in room. player[%llu,%llu][%llu]", 
			player.GateId(), player.ClientId(), player.UserId() );
        return;
    }

    if( player.State() == CPlayerBase::E_PlayerState_Hall )
	{
		LOG_ERROR( "PlayerStandUp player state error. player[%llu,%llu][%llu] state[%d]", 
			player.GateId(), player.ClientId(), player.UserId(), player.State() );
		return;
	}

	s32 ret = room->CanStandUp( player );
    commonproto::SCStandUpRsp rsp;
	rsp.result = ret;
	player.SendMsg( commonproto::SC_STANDUP_RSP, rsp );

	LOG_INFO( "[%s][%s][%d] user[%llu] room[%d] seatno[%d] ret[%d]",
		__FILE__, __FUNCTION__, __LINE__, player.UserId(), room->Id(), player.GetSeatNo(), ret );
    if( ret == errorcode::E_ErrorCode_Success )
    {
        room->PlayerStandUp( player );
    }
}

void CHall::PlayerReady(CPlayerBase &player)
{
    CRoomBase *room = player.GetRoom();
    commonproto::SCReadyRsp rsp;
    rsp.ret = errorcode::E_ErrorCode_Success;
	if( !room )
    {
		LOG_ERROR( "PlayerReady player not in room. player[%llu,%llu][%llu]", 
			player.GateId(), player.ClientId(), player.UserId() );
        rsp.ret = errorcode::E_ErrorCode_NotInRoom;
        player.SendMsg(commonproto::SC_READY_RSP, rsp);
        return;
    }
    
    if( player.State() != CPlayerBase::E_PlayerState_WaitInRoom ||
        room->State() == CRoomBase::E_RoomState_Gaming )
	{
		LOG_ERROR( "PlayerReady state error. player[%llu,%llu][%llu] player_state[%d] room_state[%d]", 
			player.GateId(), player.ClientId(), player.UserId(), player.State(), room->State() );
        rsp.ret = errorcode::E_ErrorCode_StateError;
        player.SendMsg(commonproto::SC_READY_RSP, rsp);
		return;
	}
	
	s32 ret = room->CanReady( player );
	LOG_INFO( "[%s][%s][%d] user[%llu] room[%d] seatno[%d] ret[%d]",
		__FILE__, __FUNCTION__, __LINE__, player.UserId(), room->Id(), player.GetSeatNo(), ret );
    if( ret == errorcode::E_ErrorCode_Success )
	{
        player.SendMsg(commonproto::SC_READY_RSP, rsp);
		room->PlayerReady( player );
	} else {
        rsp.ret = ret;     
        player.SendMsg(commonproto::SC_READY_RSP, rsp);
    }
}

void CHall::PlayerCancelReady(CPlayerBase &player)
{
	CRoomBase *room = player.GetRoom();
    if( !room )
    {
		LOG_ERROR( "PlayerCancelReady player not in room. player[%llu,%llu][%llu] state[%d]", 
			player.GateId(), player.ClientId(), player.UserId(), player.State() );
        return;
    }
    
    if( !room->PlayerInSeat(player) )
    {
		LOG_ERROR( "PlayerCancelReady player not in seat. player[%llu,%llu][%llu]", 
			player.GateId(), player.ClientId(), player.UserId() );
        return;
    }

    if( player.State() != CPlayerBase::E_PlayerState_Ready ||
	    room->State() == CRoomBase::E_RoomState_Gaming )
	{
		LOG_ERROR( "PlayerCancelReady state error. player[%llu,%llu][%llu] player_state[%d] room_state[%d]", 
			player.GateId(), player.ClientId(), player.UserId(), player.State(), room->State() );
		return;
	}

	LOG_INFO( "[%s][%s][%d] user[%llu] room[%d] seatno[%d]",
		__FILE__, __FUNCTION__, __LINE__, player.UserId(), room->Id(), player.GetSeatNo() );
	room->PlayerCancelReady( player );
}

void CHall::PlayerTrusteeShip(CPlayerBase &player)
{
    CRoomBase *room = player.GetRoom();
    if( !room )
    {
		LOG_ERROR( "PlayerTrusteeShip player not in room. player[%llu,%llu][%llu] state[%d]", 
			player.GateId(), player.ClientId(), player.UserId(), player.State() );
        return;
    }
    
    if( !room->PlayerInSeat(player) )
    {
		LOG_ERROR( "PlayerTrusteeShip player not in seat. player[%llu,%llu][%llu]", 
			player.GateId(), player.ClientId(), player.UserId() );
        return;
    }

    if( player.State() != CPlayerBase::E_PlayerState_Gaming ||
	    room->State() != CRoomBase::E_RoomState_Gaming ||
        player.IsTrusteeship() )
	{
		LOG_ERROR( "PlayerTrusteeShip state error. player[%llu,%llu][%llu] player_state[%d] room_state[%d] isTrusteeship[%d]", 
			player.GateId(), player.ClientId(), player.UserId(), player.State(), room->State(), player.IsTrusteeship()?1:0 );
		return;
	}

	LOG_INFO( "[%s][%s][%d] user[%llu] room[%d] seatno[%d]",
		__FILE__, __FUNCTION__, __LINE__, player.UserId(), room->Id(), player.GetSeatNo() );
	room->PlayerTrusteeShip( player );
}

void CHall::PlayerCancelTrusteeShip(CPlayerBase &player)
{
    CRoomBase *room = player.GetRoom();
    if( !room )
    {
		LOG_ERROR( "PlayerCancelTrusteeShip player not in room. player[%llu,%llu][%llu] state[%d]", 
			player.GateId(), player.ClientId(), player.UserId(), player.State() );
        return;
    }
    
    if( !room->PlayerInSeat(player) )
    {
		LOG_ERROR( "PlayerCancelTrusteeShip player not in seat. player[%llu,%llu][%llu]", 
			player.GateId(), player.ClientId(), player.UserId() );
        return;
    }

    if( player.State() != CPlayerBase::E_PlayerState_Gaming ||
	    room->State() != CRoomBase::E_RoomState_Gaming ||
        !player.IsTrusteeship() )
	{
		LOG_ERROR( "PlayerCancelTrusteeShip state error. player[%llu,%llu][%llu] player_state[%d] room_state[%d] isTrusteeship[%d]", 
			player.GateId(), player.ClientId(), player.UserId(), player.State(), room->State(), player.IsTrusteeship()?1:0 );
		return;
	}

	LOG_INFO( "[%s][%s][%d] user[%llu] room[%d] seatno[%d]",
		__FILE__, __FUNCTION__, __LINE__, player.UserId(), room->Id(), player.GetSeatNo() );
	room->PlayerCancelTrusteeShip( player );
}

void CHall::PlayerRoomChat(CPlayerBase &player, s8 chattype, const std::string &chatcontent, s8 anonymous, std::vector<u64> &receiver, s8 isend, std::vector<std::string> &param)
{
    CRoomBase *room = player.GetRoom();
    if( !room )
    {
		LOG_ERROR( "PlayerRoomChat player not in room. player[%llu,%llu][%llu] state[%d] chattype[%d] anonymous[%d] receiverSZ[%d]", 
			player.GateId(), player.ClientId(), player.UserId(), player.State(), chattype, anonymous, receiver.size() );
        return;
    }

    room->PlayerRoomChat( player, chattype, chatcontent, anonymous, receiver, isend, param );
}

void CHall::PlayerCreateRoom(CPlayerBase &player, const std::string &name, const std::string &passwd, s32 ante, const std::string &data)
{
    if( player.State() != CPlayerBase::E_PlayerState_Hall )
	{
		LOG_ERROR( "PlayerCreateRoom player state error. player[%llu,%llu][%llu] state[%d]", 
			player.GateId(), player.ClientId(), player.UserId(), player.State() );
		return;
	}

    commonproto::SCCreateRoomRsp rsp;
    rsp.ret = player.CanCreateRoom( data );
    rsp.roomid = INVALID_VAL; 

    if( rsp.ret == errorcode::E_ErrorCode_Success )
    {
        rsp.roomid = CRoomManager::Instance().GetRoom();
        if( rsp.roomid == INVALID_VAL )
        {
            rsp.ret = errorcode::E_ErrorCode_NoFreeRoom;
        }
    }
	player.SendMsg( commonproto::SC_CREATE_ROOM_RSP, rsp );

    LOG_INFO( "[%s][%s][%d] user[%llu] crateroom[%u] ret[%d]", 
        __FILE__, __FUNCTION__, __LINE__, player.UserId(), rsp.roomid, rsp.ret );

    if( rsp.ret != errorcode::E_ErrorCode_Success )
    {
        return;
    }
 
    CRoomBase *room = FindRoom( rsp.roomid );
    SELF_ASSERT( room, return; );
    room->SetData( data );
    room->SetAnte( ante );
    room->SetPasswd( passwd );
    room->SetName( name );

    commonproto::SCCreateRoomNtf ntf;
    ntf.room.roomid = rsp.roomid;
    ntf.room.name = name;
    ntf.room.needpasswd = (passwd!="");
    ntf.room.ante = ante;
    ntf.room.curcount = 0;
    ntf.room.maxcount = MaxRoomPlayerCount();
    ntf.room.data = data;
    BroadcastMsg( commonproto::SC_CREATE_ROOM_NTF, ntf );

    player.OnCreateRoom( rsp.roomid, data );
    
    // ???????????????,????????????????
    // ???????????????????????,??????????
    // ???????????????????room?????
    PlayerEnterRoom( player, *room, 0, "" );
}

void CHall::PlayerMatchRequest(CPlayerBase &player)
{
    // 玩家请求匹配
    // 如果玩家在游戏中不允许匹配

    // 调整玩家匹配队列, 如果有多个匹配队列，可以保证下次匹配时主动换桌的玩家
    // 可以不和之前的人匹配到一起
    s32 oldidx = CTeamManager::Instance().GetUserQueIdx( player.UserId() );
    CTeamManager::Instance().SetUserQueIdx( player.UserId(), oldidx + 1 );
   
    commonproto::SCMatchPlayerRsp rsp;
    rsp.ret = errorcode::E_ErrorCode_Success;
    CRoomBase *room = player.GetRoom();
    if( room )
    {
        if( room->PlayerIsBeholder(player) )
        {
            // 玩家是旁观, 离开房间后可以匹配
            room->PlayerLeave( player, commonproto::E_LeaveReason_SelfOp );
        }
        else if( room->State() != CRoomBase::E_RoomState_Gaming )
        {
            // 玩家在座位上游戏尚未开始 , 解散房间后可以匹配
            // 房间内玩家重新匹配
            DissolveRoomReMatch( *room );
            return;
        }
        else
        {
            // 不允许匹配
            rsp.ret = errorcode::E_ErrorCode_InGaming;
        }
    }

    player.SendMsg( commonproto::SC_MATCH_PLAYER_RSP, rsp );
    if( rsp.ret == errorcode::E_ErrorCode_Success )
    {
        CTeamManager::Instance().AddUser( player.UserId() );
    }
}

void CHall::PlayerSetRoomAnte(CPlayerBase &player, s32 ante)
{
    CRoomBase *room = player.GetRoom();
	if( !room )
    {
		LOG_ERROR( "PlayerSetRoomAnte player not in room. player[%llu,%llu][%llu]", 
			player.GateId(), player.ClientId(), player.UserId() );
        return;
    }
    
    if( !room->PlayerInSeat(player) )
    {
		LOG_ERROR( "PlayerSetRoomAnte player not in seat. player[%llu,%llu][%llu]", 
			player.GateId(), player.ClientId(), player.UserId() );
        return;
    }

	s32 ret = room->CanSetRoomAnte( player, ante );
	LOG_INFO( "[%s][%s][%d] user[%llu] room[%d] seatno[%d] ante[%d] ret[%d]",
		__FILE__, __FUNCTION__, __LINE__, player.UserId(), room->Id(), player.GetSeatNo(), ante, ret );
    if( ret == errorcode::E_ErrorCode_Success )
	{
		room->PlayerSetAnte( player, ante );
	}
}

void CHall::PlayerGetCenterMoneyDone(CPlayerBase &player, std::vector<s64> &money, commonproto::OnlineData &onlineinfo)
{
    s32 gameid = m_gameid;
    u64 serverid = CServerManager::Instance().GetId();
    if( onlineinfo.gameid == 0 && onlineinfo.serverid == 0 )
    {
        player.m_basicInfo.money = money;
        if( (CHallConfig::Instance().GetCfg().roomMoneyUpLimit > 0 && 
                player.GetMoney(commonproto::E_MoneyType_1) > CHallConfig::Instance().GetCfg().roomMoneyUpLimit) ||
            (CHallConfig::Instance().GetCfg().roomMoneyBottomLimit > 0 && 
                player.GetMoney(commonproto::E_MoneyType_1) < CHallConfig::Instance().GetCfg().roomMoneyBottomLimit) )
        {
            commonproto::SCGameAuthenRsp rsp;
            rsp.result = errorcode::E_ErrorCode_NotEnoughMoney;
            APPEND_INT32(rsp.data, onlineinfo.gameid);
            APPEND_INT64(rsp.data, onlineinfo.serverid);
            player.SendMsg( commonproto::SC_GAME_AUTHEN_RSP, rsp );
	    
            LOG_INFO( "[%s][%s][%d] player[%llu,%llu][%llu] result[%d] kickout", 
		        __FILE__, __FUNCTION__, __LINE__, 
                player.GateId(), player.ClientId(), player.UserId(), rsp.result );
        
            CHall::Instance().Close( player.GateId(), player.ClientId() );
            return;
        }

        // 正常流程，登陆成功
        commonproto::SCGameAuthenRsp rsp;
        rsp.result = errorcode::E_ErrorCode_Success;
        player._DumpUserInfo( rsp.data );
        rsp.gamedata = player.GetGameData();
        player.SendMsg( commonproto::SC_GAME_AUTHEN_RSP, rsp );
        _LoadUserActivityData( player );
        player.OnEnterHall();
        _LoadUserItems( player );
    }
    else if( onlineinfo.gameid == gameid && onlineinfo.serverid == serverid )
    {
        // 这种情况出现在玩家登陆,在消息还没从center返回到当前服务器前
        // 玩家断线后又登陆成功，此时会收到2个getmoney消息，第2个会走到这里
        // 忽略掉
	    LOG_WARN( "[%s][%s][%d] user[%llu]",
		    __FILE__, __FUNCTION__, __LINE__, player.UserId() );
        player.m_basicInfo.money = money;
        commonproto::SCGameAuthenRsp rsp;
        rsp.result = errorcode::E_ErrorCode_Success;
        player._DumpUserInfo( rsp.data );
        rsp.gamedata = player.GetGameData();
        player.SendMsg( commonproto::SC_GAME_AUTHEN_RSP, rsp );
        _LoadUserActivityData( player );
        player.OnEnterHall();
        _LoadUserItems( player );
    }
    else
    {
        // 已经在其他游戏中，不允许登陆了
        commonproto::SCGameAuthenRsp rsp;
        rsp.result = errorcode::E_ErrorCode_AleardyLoginGame;
        APPEND_INT32(rsp.data, onlineinfo.gameid);
        APPEND_INT64(rsp.data, onlineinfo.serverid);
        player.SendMsg( commonproto::SC_GAME_AUTHEN_RSP, rsp );
	    
        LOG_INFO( "[%s][%s][%d] player[%llu,%llu][%llu] result[%d] kickout", 
		    __FILE__, __FUNCTION__, __LINE__, 
            player.GateId(), player.ClientId(), player.UserId(), rsp.result );
        
        // 踢出大厅
        CHall::Instance().Close( player.GateId(), player.ClientId() );
    }
}

void CHall::PlayerGetRoomList(CPlayerBase &player)
{
    const int GROUP = 100;
    int n = 0;
    int tn = 0;
    commonproto::SCGetRoomListRsp rsp;

    std::set<s32>::const_iterator it = CRoomManager::Instance().GetUsingList().begin();
    for( ; it != CRoomManager::Instance().GetUsingList().end(); ++it )
    {
	    CRoomBase *room = FindRoom( *it );
        SELF_ASSERT( room, continue; );
        commonproto::RoomBasicInfo info;
        room->DumpBasicInfo( info );
        rsp.rooms.push_back( info );
        ++n;
        ++tn;

        if( n >= GROUP )
        {
            player.SendMsg( commonproto::SC_GET_ROOM_LIST_RSP, rsp );
            n = 0;
            rsp.rooms.clear();
        }
    }
    if( n > 0 )
    {
        player.SendMsg( commonproto::SC_GET_ROOM_LIST_RSP, rsp );
    }
    LOG_INFO( "[%s][%s][%d] player[%llu,%llu][%llu] roomcount[%d]", 
        __FILE__, __FUNCTION__, __LINE__, 
        player.GateId(), player.ClientId(), player.UserId(), tn );
}

void CHall::PlayerGetActivityAward(CPlayerBase &player, s32 activityid)
{
    player.GetActivityAward( activityid );
}

void CHall::PlayerDismissFriendRoom(CPlayerBase &player)
{
    CRoomBase *room = player.GetRoom();
    if( !room )
    {
        LOG_ERROR( "[%s] player not in room. player[%llu,%llu][%llu]", __FUNCTION__,
                player.GateId(), player.ClientId(), player.UserId() );
        return;
    }
    LOG_DEBUG( "[%s] player[%llu]", __FUNCTION__, player.UserId() );
    room->DismissFriendRoom( player );
}

void CHall::PlayerLeaveFriendRoom(CPlayerBase &player)
{
    CRoomBase *room = player.GetRoom();
    if( !room )
    {
        LOG_ERROR( "[%s] player not in room. player[%llu,%llu][%llu]", __FUNCTION__,
            player.GateId(), player.ClientId(), player.UserId() );
        return;
    }

    room->LeaveFriendRoom( player );
}

void CHall::PlayerAgreeDismissFriendRoom(CPlayerBase &player, s32 agree)
{
    CRoomBase *room = player.GetRoom();
    if( !room )
    {
        LOG_ERROR( "[%s] player not in room. player[%llu,%llu][%llu]", __FUNCTION__,
            player.GateId(), player.ClientId(), player.UserId() );
        return;
    }

    room->AgreeDismissFriendRoom( player, agree, false );
}

void CHall::PlayerStartGameFriendRoom(CPlayerBase &player)
{
    CRoomBase *room = player.GetRoom();
    if( !room )
    {
        LOG_ERROR( "[%s] player not in room. player[%llu,%llu][%llu]", __FUNCTION__,
                player.GateId(), player.ClientId(), player.UserId() );
        return;
    }

    room->StartGameFriendRoom( player );
}

void CHall::KickOutRoom(CPlayerBase &player, u64 kickuserid)
{
    CRoomBase *room = player.GetRoom();
    if( !room )
    {
        LOG_ERROR( "[%s] not found room. player[%llu,%llu][%llu]", 
            __FUNCTION__, player.GateId(), player.ClientId(), player.UserId() );
        return;
    }

    commonproto::SCKickOutRoomRsp rsp;
    rsp.kickuser = kickuserid;
    rsp.result = room->CanKickOut( player, kickuserid );
    player.SendMsg( commonproto::SC_KICKOUT_ROOM_RSP, rsp );
    LOG_INFO( "[%s] player[%llu,%llu][%llu] kick[%llu] ret[%d]", 
        __FUNCTION__, player.GateId(), player.ClientId(), player.UserId(),
        kickuserid, rsp.result );

    if( rsp.result == errorcode::E_ErrorCode_Success )
    {
        commonproto::SCKickOutRoomNtf ntf;
        ntf.kickuser = kickuserid;
        room->BroadcastMsg( commonproto::SC_KICKOUT_ROOM_NTF, ntf );
        room->KickOutRoom( player, kickuserid );
    }
}

void CHall::UseInteractItem(CPlayerBase &player, s32 to, s32 item)
{
    CRoomBase *room = player.GetRoom();
    if( !room )
    {
        LOG_ERROR( "[%s] not found room. player[%llu,%llu][%llu]", 
            __FUNCTION__, player.GateId(), player.ClientId(), player.UserId() );
        return;
    }
    commonproto::SCUseInteractItemRsp rsp;
    rsp.result = room->CanUseInteractItem(player, to, item);
    rsp.toseat = to;
    rsp.item = item;
    player.SendMsg( commonproto::SC_USE_INTERACT_ITEM_RSP, rsp );
    LOG_INFO( "[%s] player[%llu,%llu][%llu] to[%d] item[%d] ret[%d]", 
        __FUNCTION__, player.GateId(), player.ClientId(), player.UserId(),
        to, item, rsp.result );
    if (rsp.result == errorcode::E_ErrorCode_Success) {
        commonproto::SCUseInteractItemNtf ntf;
        ntf.toseat = to;
        ntf.item = item;
        ntf.fromseat = player.m_seatno;
        room->BroadcastMsg( commonproto::SC_USE_INTERACT_ITEM_NTF, ntf );
        room->UseInteractItem(player, to, item);
    }
}

void CHall::UserCuiPai(CPlayerBase &player, commonproto::UserCuiPaiCommon &cuipai)
{
    CRoomBase *room = player.GetRoom();
    if( !room )
    {
        LOG_ERROR( "[%s] not found room. player[%llu,%llu][%llu]", 
            __FUNCTION__, player.GateId(), player.ClientId(), player.UserId() );
        return;
    }
    cuipai.seat = player.GetSeatNo();
    cuipai.sex = player.GetBasicInfo().sex;
    commonproto::SCUserCuiPaiNtf ntf;
    ntf.cuipai = cuipai;


    LOG_INFO( "[%s] player[%llu,%llu][%llu] seat[%d] type[%d] sex[%d]", 
        __FUNCTION__, player.GateId(), player.ClientId(), player.UserId(),
        cuipai.seat, cuipai.cptype, cuipai.sex );
    room->BroadcastMsg( commonproto::SC_USER_CUIPAI_NTF, ntf );
}

void CHall::GetUserInfo(CPlayerBase &player, u64 userid)
{
    LOG_DEBUG( "[%s] player[%llu] getuser[%llu]", 
        __FUNCTION__, player.UserId(), userid );

    commonproto::SCGetUserInfoRsp rsp;
    rsp.result = errorcode::E_ErrorCode_NotFoundUser;
    CPlayerBase *p = FindPlayer( userid );
    if( p )
    {
        rsp.result = errorcode::E_ErrorCode_Success;
        rsp.basicinfo = p->GetBasicInfo();
        rsp.gamedata = p->GetGameData();
        rsp.info = p->GetLocation();
    }
    player.SendMsg( commonproto::SC_GET_USER_INFO_RSP, rsp );
}

void CHall::StartTimer()
{
	char addr[16] = {0};
	*((u64*)addr) = (u64)this;
	m_roomTimerId = CServerManager::Instance().AddTimer( 1000, CHall::_CheckRoomTimeOutTimer, addr, sizeof(u64), true );
    m_logTimerId = CServerManager::Instance().AddTimer( 60000, CHall::_CheckGameLogTimer, addr, sizeof(u64), true );
    m_resTimerId = CServerManager::Instance().AddTimer( 3600000, CHall::_LoadResTimer, addr, sizeof(u64), true );
    m_gameTimesTimerId = CServerManager::Instance().AddTimer( 30000, CHall::_UpdateGameTimesTimer, addr, sizeof(u64), true );
}

bool CHall::SendMsg2Server(u64 serverid, u32 msgid, const IMessage &msg)
{
	CConnSession *server = CSessionManager::Instance().FindRpcServer( serverid );
	if( !server )
	{
		LOG_ERROR( "[%s][%s][%d] failed. server[%d] msgid[%u]", 
			__FILE__, __FUNCTION__, __LINE__, serverid, msgid );
		return false;
	}
	server->SendMsg( msgid, msg );
    return true;
}

bool CHall::SendMsg2Server(u64 serverid, const byte *data, s32 len)
{
    CConnSession *server = CSessionManager::Instance().FindRpcServer( serverid );
	if( !server )
	{
		LOG_ERROR( "[%s][%s][%d] failed. server[%d] len[%d]", 
			__FILE__, __FUNCTION__, __LINE__, serverid, len );
		return false;
	}
	server->SendMsg( data, len );
    return true;
}

bool CHall::SendMsg2DBProxy(u64 dbserverid, u32 msgid, IMessage &msg, s32 dbid, u64 syncid)
{
    char _syncid = (char)(syncid % 0x7F);
    char head[8] = {0};
    *((s32*)head) = dbid;
    *(head+sizeof(s32)) = _syncid;
    s32 headlen = sizeof(s32) + sizeof(char);

    CConnSession *server = CSessionManager::Instance().FindRpcServer( dbserverid );
    if( !server )
    {
        LOG_ERROR( "[%s][%s][%d] failed. dbserver[%d] msgid[%u]", 
                __FILE__, __FUNCTION__, __LINE__, dbserverid, msgid );
        return false;
    }
    server->SendMsgWithHead( msgid, msg, head, headlen );
    return true;
}

bool CHall::SendMsg2DBProxy(u32 msgid, IMessage &msg, u64 syncid)
{
    static s32 DB_MAIN_ID = 1;
    return SendMsg2DBProxy( m_dbServerId, msgid, msg, DB_MAIN_ID, syncid ); 
}

bool CHall::SendLogMsg2DBProxy(u32 msgid, IMessage &msg, u64 syncid)
{
    static s32 DB_LOG_ID = 2;
    return SendMsg2DBProxy( m_dbServerId, msgid, msg, DB_LOG_ID, syncid ); 
}

bool CHall::NotifyDBProxyExecSQL(u64 dbserverid, const std::string &sql, s32 dbid, u64 syncid)
{
    dbcommon::ServerDBProxyExecSql msg;
    msg.sql = sql;
    return SendMsg2DBProxy( dbserverid, dbcommon::SERVER_DBPROXY_EXEC_SQL, msg, dbid, syncid );
}

bool CHall::NotifyDBProxyExecSQL(const std::string &sql, u64 syncid)
{
    static s32 DB_MAIN_ID = 1;
    return NotifyDBProxyExecSQL( m_dbServerId, sql, DB_MAIN_ID, syncid );
}

bool CHall::NotifyDBProxyExecSQL(const char *sql, u64 syncid)
{
    return NotifyDBProxyExecSQL( string(sql), syncid );
}

void CHall::UpdateGameTimes2DBProxy(CRoomBase *proom, CPlayerBase *pplayer, s32 nd)
{
	dbcommon::GameDBProxyUpdateGameTimes m;
	m.nd = nd;
	if (proom) {
		CPlayerBase *pp = NULL;
		for (s32 i = 0; i != m_maxRoomPlayerCount; ++i) {
			pp = proom->GetPlayerInSeat(i);
			if (pp) {
				m.userid = pp->UserId();
				m.times = pp->ClearGameTimes();
				m.nickname = pp->GetBasicInfo().nickname;
				if (m.times > 0)
					SendMsg2DBProxy(dbcommon::GAME_DBPROXY_UPDATE_GAMETIMES, m, pp->UserId());			
			}
		}	
	}

	if (pplayer) {
		m.userid = pplayer->UserId();
		m.times = pplayer->ClearGameTimes();
		m.nickname = pplayer->GetBasicInfo().nickname;
		if (m.times > 0)
			SendMsg2DBProxy(dbcommon::GAME_DBPROXY_UPDATE_GAMETIMES, m, pplayer->UserId());
	}
}

void CHall::SendMsg2Center(u32 msgid, IMessage &msg)
{
    SendMsg2Server(m_centerServerId, msgid, msg);
}

void CHall::DumpAllPlayers(std::vector<u64> &vec)
{
	vec.clear();
	std::map<u64, CPlayerBase*>::iterator it = m_playersIpMap.begin();
	for( ; it != m_playersIpMap.end(); ++it )
	{
		vec.push_back( it->first );
	}
}

void CHall::GetUserMoneyInfo(CPlayerBase &player, bool onlineSet)
{
    center::ServerCenterGetUserMoneyReq req;
    req.userid = player.UserId();
    req.curmoney = player.GetBasicInfo().money;
    req.onlineset = onlineSet?1:0;
    req.gameid = m_gameid;
    req.serverid = CServerManager::Instance().GetId();
    req.gamemode = CHallConfig::Instance().GetCfg().gameMode;
    req.roommode = CHallConfig::Instance().GetCfg().roomMode;

	bool ret = SendMsg2Server( 
        m_centerServerId, 
        msgid::SERVER_CENTER_GET_USER_MONEY_REQ, req );
    if( !ret )
    {
		LOG_ERROR( "[%s][%s][%d] SendMsg2Server failed.. centerserver[%llu] user[%llu]", 
			__FILE__, __FUNCTION__, __LINE__, m_centerServerId, req.userid );
        Close( player.GateId(), player.ClientId() );
    }
}

void CHall::UpdateUserMoney(u64 userid, std::vector<s64> &upmoney, s32 reason)
{
    center::ServerCenterUpdateMoneyReq req;
    req.userid = userid;
    req.upmoney = upmoney;
    req.reason = reason;
	bool ret = SendMsg2Server( 
        m_centerServerId, 
        msgid::SERVER_CENTER_UPDATE_USER_MONEY_REQ, req );
    if( !ret )
    {
		LOG_ERROR( "[%s][%s][%d] SendMsg2Server failed.. centerserver[%llu] user[%llu]", 
			__FILE__, __FUNCTION__, __LINE__, m_centerServerId, req.userid );
    }
}

void CHall::DissolveRoomReMatch(CRoomBase &room)
{
    commonproto::SCMatchPlayerRsp rsp;
    rsp.ret = errorcode::E_ErrorCode_Success;

    vector<CPlayerBase*> players[2];
    vector<char> isready;
    room.DumpAllSeatPlayers( players[0], isready );
    room.DumpAllBeholderPlayers( players[1] );
    // 房间解散
    room.Dissolve();
    // 重新加入匹配队列
    for( int i=0; i<2; ++i )
    {
        vector<CPlayerBase*>::iterator it = players[i].begin();
        for( int j=0; it != players[i].end(); ++it, ++j )
        {
            if( (*it) )
            {
                s32 rematch = 0;
                if( i==0 && isready[j]==1 )
                {
                    rematch = 1;
                    (*it)->SendMsg( commonproto::SC_MATCH_PLAYER_RSP, rsp );
                    CTeamManager::Instance().AddUser( (*it)->UserId() );
                }
		
                LOG_INFO( "[%s][%s][%d] user[%llu] room[%d] rematch[%d]", 
			        __FILE__, __FUNCTION__, __LINE__, (*it)->UserId(), room.Id(), rematch );
            }
        }
    }
}

void CHall::AddGameLog(u64 userid, s32 gameid, u64 serverid, s32 roomid, u64 battleid, s64 winmoney, s32 tax, s8 isoffline, s8 isrobot, u64 tbegin, u64 tend, std::string &channel, s32 reserve1, s32 reserve2, const char *reserve3)
{
    if( m_gamelogMgr )
    {
        m_gamelogMgr->AddGameLog( userid, gameid, serverid, roomid, battleid, winmoney, tax, isoffline, isrobot, tbegin, tend, channel, reserve1, reserve2, reserve3 );
    }
}

void CHall::BroadcastUserEnterHall(CPlayerBase &player)
{
    commonproto::SCHallUserEnterNtf ntf;
    ntf.basicinfo = player.GetBasicInfo();
	BroadcastMsg( commonproto::SC_HALL_USER_ENTER_NTF, ntf );
}

void CHall::BroadcastUserLeaveHall(CPlayerBase &player)
{
    commonproto::SCHallUserLeaveNtf ntf;
    ntf.userid = player.UserId();
	BroadcastMsg( commonproto::SC_HALL_USER_LEAVE_NTF, ntf );
}

void CHall::BroadcastUserEnterRoom(CPlayerBase &player, s32 roomid, s32 seatno)
{
    commonproto::SCRoomUserEnterNtf ntf;
    ntf.roomid = roomid;
    ntf.userid = player.UserId();
    ntf.seatno = seatno;
	BroadcastMsg( commonproto::SC_ROOM_USER_ENTER_NTF, ntf );
}

void CHall::BroadcastUserLeaveRoom(CPlayerBase &player, s32 roomid, s32 seatno)
{
    commonproto::SCRoomUserLeaveNtf ntf;
    ntf.roomid = roomid;
    ntf.userid = player.UserId();
    ntf.seatno = seatno;
	BroadcastMsg( commonproto::SC_ROOM_USER_LEAVE_NTF, ntf );
}

bool CHall::InitActivityData(CPlayerBase &player, const ActivityItem &activity, void *activityData)
{
    if( m_activityMgr )
    {
        return m_activityMgr->InitActivityData( m_gameid, player, activity, activityData );
    }
    return false;
}

bool CHall::GameEndUpdateActivity(CPlayerBase &player, const ActivityItem &activity, void *activityData)
{
    if( m_activityMgr )
    {
        return m_activityMgr->GameEndUpdateActivity( m_gameid, player, activity, activityData );
    }
    return false;
}

int CHall::CheckActivityState(const ActivityItem &activity, void *activityData)
{
    if( m_activityMgr )
    {
        return m_activityMgr->CheckActivityState( m_gameid, activity, activityData );
    }
    return commonproto::E_ActivityState_NoChange;
}

void CHall::GetActivityAwardDone(const ActivityItem &activity, void *activityData)
{
    if( m_activityMgr )
    {
        m_activityMgr->GetActivityAwardDone( m_gameid, activity, activityData );
    }
}

void CHall::ReloadResource()
{
    CActivityConfigManager::Instance().Load( m_activityFile.c_str() );
    CServerManager::Instance().ReloadServerConfig();
}

bool CHall::IsFriendMode()
{
    return (CHallConfig::Instance().GetCfg().roomMode == E_RoomMode_Friend);
}

void CHall::_Init()
{
    m_activityMgr = new CActivityManager();
    m_activityMgr->Init();

    // UDP
    bool ret = m_udpclient.Start(
        CHallConfig::Instance().GetCfg().udpIp.c_str(),
        CHallConfig::Instance().GetCfg().udpPort );
    m_udpclient.m_passwd = CHallConfig::Instance().GetCfg().udpPasswd;

    LOG_INFO( "[%s][%s][%d] gamemode[%d] roommode[%d] pause[%d] udp[%d][%s:%d][%s] roomMoneyBottomLimit[%d]", 
        __FILE__, __FUNCTION__, __LINE__,
        CHallConfig::Instance().GetCfg().gameMode,
        CHallConfig::Instance().GetCfg().roomMode,
        CHallConfig::Instance().GetCfg().pauseDismissRoom, ret?1:0,
        CHallConfig::Instance().GetCfg().udpIp.c_str(),
        CHallConfig::Instance().GetCfg().udpPort,
        CHallConfig::Instance().GetCfg().udpPasswd.c_str(),
        CHallConfig::Instance().GetCfg().roomMoneyBottomLimit);
}

void CHall::_AddPlayer(u64 gateid, u64 clientid, u64 userid, CPlayerBase &player)
{
	m_playersIpMap[ userid ] = &player;
	m_playersPosMap[ gateid ][ clientid ] = &player;
}

bool CHall::_RemovePlayer(u64 gateid, u64 clientid, u64 userid)
{
	bool rm1 = false;
	map<u64, map<u64, CPlayerBase*> >::iterator it = m_playersPosMap.find( gateid );
	if( it != m_playersPosMap.end() )
	{
		map<u64, CPlayerBase*>::iterator _it = it->second.find( clientid );
		if( _it != it->second.end() )
		{
			it->second.erase( _it );
			rm1 = true;	
		}
	}
	
	bool rm2 = false;
	map<u64, CPlayerBase*>::iterator itr = m_playersIpMap.find( userid );
	if( itr != m_playersIpMap.end() )
	{
		m_playersIpMap.erase( itr );
		rm2 = true;
	}

	return (rm1 & rm2);
}

CPlayerBase* CHall::_GetFreePlayer()
{
	CPlayerBase *player = NULL;
	if( m_freeList.size() > 0 )
	{
		player = (*m_freeList.begin());
		m_freeList.pop_front();
	}
	else
	{
		SELF_ASSERT( m_playerTemplate, return NULL; );
		player = m_playerTemplate->Clone();
	}
	return player;
}

void CHall::_PutPlayer(CPlayerBase *player)
{
	SELF_ASSERT( player, return; );
	m_freeList.push_back( player );
}

void CHall::_CheckRoomTimeOutTimer(void *data, s32 len)
{
    u64 addr = *((u64*)data);
    CHall *pthis = (CHall*)addr;

    u64 now = (u64)time(NULL);
    for( s32 i=0; i<pthis->m_roomCount; ++i )
    {
        if( pthis->m_rooms[i] && pthis->m_rooms[i]->State() != CRoomBase::E_RoomState_Idle )
        {
            pthis->m_rooms[i]->CheckActionTimeOut( now );
            pthis->m_rooms[i]->CheckTimeOut();
            pthis->m_rooms[i]->CheckMoreTimeOut( now );
        }
    }

    static u64 lastNotify = TIME_NOW;
    if( now - lastNotify >= 60 )
    {
        lastNotify = now;
        CHall::Instance().NotifyRoomCenterRoomStatus();
    }
}

void CHall::_CheckGameLogTimer(void *data, s32 len)
{
    // ÿX???Ӽ???һ???Ƿ???Ҫд??־
    u64 addr = *((u64*)data);
	CHall *pthis = (CHall*)addr;
    pthis->m_gamelogMgr->Check2Log();
    pthis->_ReportOnlineCount();
}

void CHall::_LoadResTimer(void *data, s32 len)
{
    u64 addr = *((u64*)data);
	CHall *pthis = (CHall*)addr;
    pthis->ReloadResource();
}

void CHall::_UpdateGameTimesTimer(void *data, s32 len)
{
	u64 addr = *((u64*)data);
	CHall *pthis = (CHall*)addr;
	for( s32 i=0; i<pthis->m_roomCount; ++i )
    {
        if( pthis->m_rooms[i])
        {
			s32 nd = 0;
			s64 st = pthis->m_rooms[i]->GetGameStartTime();
			if (0 != st && !IsSameDay(st, TIME_NOW))
				nd = 1;
			pthis->UpdateGameTimes2DBProxy(pthis->m_rooms[i], NULL, nd);
        }
    }

    pthis->NotifyBalanceGameData();
}

void CHall::_BreakUserComeBack(CPlayerBase &old, u64 userid, u64 gateid, u64 clientid, std::string &token)
{
    if( old.GateId() != gateid || old.ClientId() != clientid )
    {
        LOG_WARN( "_BreakUserComeBack old player online. close all. gateid[%llu] clientid[%llu] user[%llu] old[%llu,%llu]", 
            gateid, clientid, userid,
            old.GateId(), old.ClientId() );

        // close old
        commonproto::SCKickOutNtf ntf;
        ntf.reason = errorcode::E_ErrorCode_RepeatLogin;
        old.SendMsg( commonproto::SC_KICK_OUT_NTF, ntf );
        old.Close();

        // again login
        _RemovePlayer( old.GateId(), old.ClientId(), userid );
        // may false after gate restart.
        //SELF_ASSERT( ret, return; ); 
        old.ResetPlayer( gateid, clientid );
        _AddPlayer( gateid, clientid, userid, old );
        _DoBreakUserComeBack( old, token );
    }
    else
    {
        // 同一个连接发送重复的登陆请求, 忽略
    }
}

void CHall::_DoBreakUserComeBack(CPlayerBase &player, std::string &token)
{
    CRoomBase *room = player.GetRoom();
    if( room )
    {
        room->NotifyFriendRoomInfo( player );
    }

    if( player.OnBreakEnterHall( token ) )
    {
        player.SetOffline( false );

        if( room )
        {
            commonproto::SCUserStateNtf ntf;
            ntf.state = player.AddiStatus();
            ntf.seat = player.GetSeatNo();
            room->BroadcastMsg( commonproto::SC_USER_STATE_NTF, ntf );

            // notify location info
            room->NotifyUserLocationInfo( &player );
            // notify room dismiss progress
            room->NotifyFriendRoomDismissProgress( player );
            if (player.GetSeatNo() == room->GetPrioritySeatno()) {
                commonproto::SCFriendRoomPrioritySeatnoNtf ntf2;
                ntf2.seat = room->GetPrioritySeatno();
                player.SendMsg( commonproto::SC_FRIEND_ROOM_PRIORITY_SEATNO, ntf2 );
            }
        }
		// notify activity progress
        player.NotifyActivityProgress();
    }
    else
    {
        player.Close();
    }
}

void CHall::_NotifyCenterUserOnline(u64 userid)
{
    center::ServerCenterUserOnline msg;
    msg.userid = userid;
    msg.gameid = m_gameid;
    msg.serverid = CServerManager::Instance().GetId();
    msg.gamemode = CHallConfig::Instance().GetCfg().gameMode;
    msg.roommode = CHallConfig::Instance().GetCfg().roomMode;
    if( !SendMsg2Server(m_centerServerId, msgid::SERVER_CENTER_USER_ONLINE, msg) )
    {
        LOG_ERROR( "[%s][%s][%d] user[%llu] gameid[%d] serverid[%llu]", 
            __FILE__, __FUNCTION__, __LINE__,
            msg.userid, msg.gameid, msg.serverid );
    }
}

void CHall::_NotifyCenterUserOffline(u64 userid)
{
    center::ServerCenterUserOffline msg;
    msg.userid = userid;
    msg.gameid = m_gameid;
    msg.serverid = CServerManager::Instance().GetId();
    msg.gamemode = CHallConfig::Instance().GetCfg().gameMode;
    msg.roommode = CHallConfig::Instance().GetCfg().roomMode;
    if( !SendMsg2Server(m_centerServerId, msgid::SERVER_CENTER_USER_OFFLINE, msg) )
    {
        LOG_ERROR( "[%s][%s][%d] user[%llu] gameid[%d] serverid[%llu]", 
            __FILE__, __FUNCTION__, __LINE__,
            msg.userid, msg.gameid, msg.serverid );
    }
}

void CHall::_LoadUserActivityData(CPlayerBase &player)
{
    player.ClearActiviyData();
    u64 userid = player.UserId();
    dbcommon::GameDBProxyLoadActivityDataReq m;
    APPEND_INT64(m.bdata, userid);
    m.userid = userid;
    m.gameid = m_gameid;
    bool ret = SendMsg2DBProxy( dbcommon::GAME_DBPROXY_LOAD_ACTIVITY_DATA_REQ, m, userid );
    LOG_INFO( "[%s][%s][%d] user[%llu] sendret[%d]", 
            __FILE__, __FUNCTION__, __LINE__,
            userid, ret?1:0 );
}

void CHall::_LoadUserItems(CPlayerBase &player)
{
    player.ClearItemData();
    u64 userid = player.UserId();
    dbcommon::GameDBProxyLoadItemsReq m;
    APPEND_INT64(m.bdata, userid);
    m.userid = userid;
    bool ret = SendMsg2DBProxy( dbcommon::GAME_DBPROXY_LOAD_ITEMS_REQ, m, userid );
    LOG_INFO( "[%s][%s][%d] user[%llu] sendret[%d]", 
        __FILE__, __FUNCTION__, __LINE__,
        userid, ret?1:0 );
}

void CHall::_ReportOnlineCount()
{
    static u64 lastNotify = TIME_NOW;
    if (TIME_NOW - lastNotify < 300) {
        return; 
    }
    lastNotify = TIME_NOW;
    dbcommon::GameDBProxyReportOnlineCount m;
    m.gameid = m_gameid;
    m.serverid = CServerManager::Instance().GetId();
    m.gamemode = CHallConfig::Instance().GetCfg().gameMode;
    m.roommode = CHallConfig::Instance().GetCfg().roomMode;
    m.count = CurPlayerCount();
    LOG_INFO( "[%s][%s][%d] serverid[%llu] count[%d]", 
        __FILE__, __FUNCTION__, __LINE__,
        m.serverid, m.count);

    SendMsg2DBProxy(dbcommon::GAME_DBPROXY_REPORT_ONLINE_COUNT, m, m.gameid);
}

void CHall::NotifyRoomCenterServerStart()
{
    if( CHallConfig::Instance().GetCfg().roomMode != E_RoomMode_Friend )
    {
        return;
    }

    roomcenter::GameRoomCenterServerStart m;
    m.serverid = CServerManager::Instance().GetId();
    m.roomcount = CHallConfig::Instance().GetCfg().roomCount;
    m.maxUserCount = m_maxRoomPlayerCount; 
    m.gameid = m_gameid;

    bool ret = SendMsg2Server( CHallConfig::Instance().GetCfg().roomCenterSid,
        msgid::GAME_ROOMCENTER_SERVER_START, m );

    LOG_INFO( "[%s][%s][%d] serverid[%llu] roomcount[%d] gameid[%d] sendret[%d]", 
        __FILE__, __FUNCTION__, __LINE__, m.serverid, m.roomcount, m.gameid, ret?1:0 );
}

void CHall::NotifyRoomCenterServerStop()
{
    if( CHallConfig::Instance().GetCfg().roomMode != E_RoomMode_Friend )
    {
        return;
    }

    roomcenter::GameRoomCenterServerStop m;
    m.serverid = CServerManager::Instance().GetId();

    bool ret = SendMsg2Server( CHallConfig::Instance().GetCfg().roomCenterSid,
        msgid::GAME_ROOMCENTER_SERVER_STOP, m );

    LOG_INFO( "[%s][%s][%d] serverid[%llu] sendret[%d]", 
        __FILE__, __FUNCTION__, __LINE__, m.serverid, ret?1:0 );
}

void CHall::NotifyRoomCenterGameStart(CRoomBase &room, std::vector<u64> &uids, bool deccard)
{
    if( CHallConfig::Instance().GetCfg().roomMode != E_RoomMode_Friend )
    {
        return;
    }

    bool ret = false;
    if( room.GetFriendData()._curRound == 0 )
    {
        roomcenter::GameRoomCenterGameStart m;
        m.serverid = CServerManager::Instance().GetId();
        m.roomid = room.Id();
        m.users = uids;
        m.deccard = deccard ? 1 : 0;

        ret = SendMsg2Server( CHallConfig::Instance().GetCfg().roomCenterSid,
            msgid::GAME_ROOMCENTER_GAME_START, m );
    }
    ++room.GetFriendData()._curRound;

    LOG_INFO( "[%s][%s][%d] serverid[%llu] roomid[%d] uidSZ[%d] curRound[%d] sendret[%d] deccard[%d]", 
        __FILE__, __FUNCTION__, __LINE__, 
        CServerManager::Instance().GetId(), room.Id(), uids.size(), 
        room.GetFriendData()._curRound, ret?1:0, deccard?1:0 );
}

void CHall::NotifyRoomCenterGameStop(CRoomBase &room, s32 reason)
{
    if( CHallConfig::Instance().GetCfg().roomMode != E_RoomMode_Friend )
    {
        return;
    }

    bool ret = false;
    if( room.GetFriendData()._curRound >= room.GetFriendData()._maxRound )
    {
        roomcenter::GameRoomCenterGameStop m;
        m.serverid = CServerManager::Instance().GetId();
        m.roomid = room.Id();
        m.reason = reason;

        ret = SendMsg2Server( CHallConfig::Instance().GetCfg().roomCenterSid,
                msgid::GAME_ROOMCENTER_GAME_STOP, m );
    }

    LOG_INFO( "[%s][%s][%d] serverid[%llu] roomid[%d] reason[%d] round[%d/%d]sendret[%d]", 
        __FILE__, __FUNCTION__, __LINE__, 
        CServerManager::Instance().GetId(), room.Id(), reason, 
        room.GetFriendData()._curRound, room.GetFriendData()._maxRound, ret?1:0 );
}

void CHall::NotifyRoomCenterUserInOut(s32 roomid, u64 uid, s32 inout, u64 uuid, std::string &nickname)
{
    if( CHallConfig::Instance().GetCfg().roomMode != E_RoomMode_Friend )
    {
        return;
    }

    roomcenter::GameRoomCenterUserInOut m;
    m.serverid = CServerManager::Instance().GetId();
    m.roomid = roomid;
    m.userid = uid;
    m.inout = inout;
    m.uuid = uuid;
    m.nickname = nickname;

    bool ret = SendMsg2Server( CHallConfig::Instance().GetCfg().roomCenterSid,
        msgid::GAME_ROOMCENTER_PLAYER_INOUT, m );

    LOG_INFO( "[%s][%s][%d] serverid[%llu] roomid[%d] userid[%llu] inout[%d] sendret[%d] uuid[%llu]", 
        __FILE__, __FUNCTION__, __LINE__, m.serverid, m.roomid, m.userid, m.inout, ret?1:0, uuid );
}

void CHall::NotifyRoomCenterRoomStatus()
{
    if( CHallConfig::Instance().GetCfg().roomMode != E_RoomMode_Friend )
    {
        return;
    }

    roomcenter::GameRoomCenterRoomStatus m;
    m.serverid = CServerManager::Instance().GetId();
    for( s32 i=0; i<m_roomCount; ++i )
    {
        if( m_rooms[i]->State() == CRoomBase::E_RoomState_Idle )
        {
            m.status.push_back( roomcenter::RoomStatus_NotCreate );
        }
        else
        {
            m.status.push_back( m_rooms[i]->GetFriendData()._curRound );
        }
    }

    bool ret = SendMsg2Server( CHallConfig::Instance().GetCfg().roomCenterSid,
        msgid::GAME_ROOMCENTER_ROOM_STATUS, m );

    LOG_INFO( "[%s][%s][%d] serverid[%llu] sz[%d] sendret[%d]", 
        __FILE__, __FUNCTION__, __LINE__, m.serverid, m.status.size(), ret?1:0 );
}

void CHall::NotifyRoomCenterDecCard(CRoomBase &room)
{
    if( !CHall::Instance().IsFriendMode() )
    {
        return;
    }
    roomcenter::GameRoomCenterDecCard m;
    m.serverid = CServerManager::Instance().GetId();
    m.roomid = room.Id();
    bool ret = SendMsg2Server( CHallConfig::Instance().GetCfg().roomCenterSid,
        msgid::GAME_ROOMCENTER_DEC_CARD, m );

    LOG_INFO( "[%s][%s][%d] serverid[%llu] roomid[%d] sendret[%d]", 
        __FILE__, __FUNCTION__, __LINE__, m.serverid, m.roomid, ret?1:0 );
}

void CHall::LogFriendGameData(CPlayerBase &player, s64 score)
{
    CRoomBase *room = player.GetRoom();
    if( !room ) return;
    dbcommon::GameDBProxyFriendGameLog msg;
    msg.userid = player.UserId();
    msg.uuid = player.GetBasicInfo().uuid;
    msg.battleid = room->GetFriendData()._battleId;
    msg.score = score;
    msg.round = room->GetFriendData()._curRound;
    msg.gametime = GetNowTime();
    bool ret = SendLogMsg2DBProxy( dbcommon::GAME_DBPROXY_FRIENDGAME_LOG, msg, msg.userid );
    LOG_DEBUG( "[%s][%s][%d] user[%llu] uuid[%llu] battleid[%llu] round[%d] score[%lld] time[%s] sendret[%d]", 
        __FILE__, __FUNCTION__, __LINE__,
        msg.userid, msg.uuid, msg.battleid, msg.round, 
        msg.score, msg.gametime.c_str(), ret?1:0 );
}

void CHall::LogFriendGameRoundData(CPlayerBase &player, s32 endstate)
{
    CRoomBase *room = player.GetRoom();
    if( !room ) return;
    dbcommon::GameDBProxyFriendGameRoundLog msg;
    msg.userid = player.UserId();
    msg.uuid = player.GetBasicInfo().uuid;
    msg.headid = player.GetBasicInfo().headid;
    msg.headurl = player.GetBasicInfo().headurl;
    msg.nickname = player.GetBasicInfo().nickname;
    msg.battleid = room->GetFriendData()._battleId;
    msg.score = player.GetAllScore();
    msg.gametime = GetNowTime();
    msg.gameid = GameId();
    msg.serverid = CServerManager::Instance().GetId();
    msg.roomid = room->Id();
    msg.number = room->GetFriendData()._number;
    msg.round = room->GetFriendData()._maxRound;
    msg.endstate = endstate;
    if( endstate != commonproto::E_FRoomEnd_Normal )
    {
        msg.endstate = player.GetDismissState();
    }
    msg.creater = room->GetFriendData()._creater;
    msg.cardAA = room->GetFriendData()._cardAA;
    msg.groupid = room->GetFriendData()._groupid;
    msg.ante = room->GetFriendData()._ante;
    msg.reserve = room->GetFriendData()._reserve;
    bool ret = SendLogMsg2DBProxy( dbcommon::GAME_DBPROXY_FRIENDGAME_ROUND_LOG, msg, msg.userid );
    LOG_INFO( "[%s][%s][%d] user[%llu] uuid[%llu] battleid[%llu] score[%lld] time[%s] endstate[%d] creater[%llu] sendret[%d] AA[%d] groupid[%llu] ante[%d] reserve[%s]", 
        __FILE__, __FUNCTION__, __LINE__,
        msg.userid, msg.uuid, msg.battleid, msg.score, msg.gametime.c_str(), endstate, msg.creater, ret?1:0,
        msg.cardAA, msg.groupid, msg.ante, msg.reserve.c_str() );
}

void CHall::LogGameRecord(s32 gameid, u64 battleid, s32 round, const std::string &data, s32 isend)
{
    record::GameRecordServerGameRecords msg;
    msg.gameid = gameid;
    msg.battleid = battleid;
    msg.round = round;
    msg.data = data;
    msg.isend = isend;
    bool ret = SendMsg2Server( CHallConfig::Instance().GetCfg().recordSid,
        msgid::GAME_RECORD_SERVER_GAMERECORDS, msg );
    LOG_DEBUG( "[%s][%s][%d] battleid[%llu] sendret[%d]", 
        __FILE__, __FUNCTION__, __LINE__, msg.battleid, ret?1:0 );
}

void CHall::LogActivityAward(u64 userid, s32 activityid, s32 param1, s32 param2, s32 param3, s32 param4, s32 param5, s32 param6, s32 param7, s32 param8)
{
    dbcommon::GameDBProxyActivityAwardLog msg;
    msg.userid = userid;
    msg.gameid = GameId();
    msg.serverid = CServerManager::Instance().GetId();
    msg.activityid = activityid;
    msg.awardtime = GetNowTime();
    msg.param1 = param1;
    msg.param2 = param2;
    msg.param3 = param3;
    msg.param4 = param4;
    msg.param5 = param5;
    msg.param6 = param6;
    msg.param7 = param7;
    msg.param8 = param8;
    bool ret = SendLogMsg2DBProxy( dbcommon::GAME_DBPROXY_ACTIVITY_AWARD_LOG, msg, msg.userid );
    LOG_INFO( "[%s][%s][%d] user[%llu] sendret[%d] actid[%d] param[%d,%d,%d,%d,%d,%d,%d,%d]", 
        __FILE__, __FUNCTION__, __LINE__,
        msg.userid, ret?1:0, msg.activityid, param1, param2, param3, param4,
        param5, param6, param7, param8 );
}

void CHall::BroadcastGameNotice(const char *channel, const char *notice, const char *producer)
{
    if( !notice ) return;

    msgsvrproto::ServerNotice n;
    n.passwd = m_udpclient.m_passwd;
    n.type = msgsvrproto::E_NoticeType_Game;
    n.content = notice;
    n.limittype = 1;
    if (channel != NULL) {
        n.channels.push_back( string(channel) );
    }
    n.playcount = 1;
    n.needACK = 0;
    n.gameid = m_gameid;
    n.producer = producer;

    int flag = 0;
    int headsz = sizeof(int);
    char buf[CUDPClient::E_Msg_Len] = {0};
    int msglen = n.SerializeToArray( buf+headsz, CUDPClient::E_Msg_Len-headsz );
    if( msglen == IMessage::E_Error )
    {
        flag = -1;
    }
    else
    {
        *((int*)buf) = msgsvrproto::SERVER_NOTICE;
        msglen += sizeof(int);
        bool ret = m_udpclient.SendMsg( buf, msglen );
        flag = ret ? 0 : -2;
    }
    LOG_DEBUG( "[%s][%s][%d] channel[%s] notice[%s] flag[%d] producer[%s]", 
        __FILE__, __FUNCTION__, __LINE__, channel != NULL ? channel : "is NULL", notice, flag, producer );
}

void CHall::ReLoadGameConfig(void *data, s32 len)
{
    bool bload = CHallConfig::Instance().Load(CServerManager::Instance().GetId(), CHall::Instance().m_cfgfile.c_str());
    const HallCfg& cfg = CHallConfig::Instance().GetCfg();
    LOG_INFO( "[%s][%s][%d] bload[%d] roomMoneyBottomLimit[%d]  param[%lld,%lld,%lld,%lld,%lld] ", 
        __FILE__, __FUNCTION__, __LINE__, bload ? 1 : 0, 
        cfg.roomMoneyBottomLimit , cfg.param1, cfg.param2, cfg.param3, cfg.param4, cfg.param5);
}

void CHall::NotifyBalanceGameData()
{
    if( CHallConfig::Instance().GetCfg().roomMode != E_RoomMode_Match )
    {
        return;
    }

    CPacketParserEx parser;
    char msg[512] = {0};
    char *pdata = msg + parser.GetHeadLen();
    int len = sprintf( pdata, 
        "{\"Gid\":%d,\"Sid\":%llu,\"Num\":%d,\"Gm\":%d,\"Rm\":%d,\"Lv\":%d,\"MaxNum\":%d}",
        m_gameid, CServerManager::Instance().GetId(), CurPlayerCount(),
        CHallConfig::Instance().GetCfg().gameMode,
        CHallConfig::Instance().GetCfg().roomMode,
        CHallConfig::Instance().GetCfg().level,
        CHallConfig::Instance().MaxNum() );
    int tlen = parser.GetHeadLen() + len;
    parser.FillHeader( (byte*)msg, tlen, 1000 );

    bool ret = SendMsg2Server( 
        CHallConfig::Instance().GetCfg().balanceSid, (const byte*)msg, tlen );
    LOG_DEBUG( "[%s][%s][%d] balanceid[%llu] len[%d] data[%s] ret[%d]", 
        __FILE__, __FUNCTION__, __LINE__, 
        CHallConfig::Instance().GetCfg().balanceSid, 
        tlen, pdata, ret?1:0 );
}

